import 'dart:typed_data';

import 'package:mutex/mutex.dart';
import 'package:serial_port_win32/serial_port_win32.dart';
import 'package:get/get.dart';
import 'package:shimo_app/bus/struct/request_id.dart';
import 'frame/frame.dart';

/// 串口通信封装类 - 负责底层串口数据的发送和接收
class MySerialPort {
  late SerialPort _sp; // Win32串口实例
  List<int> _receivedData = []; // 接收到的数据缓冲区
  bool _received = false; // 数据接收标志
  int _sequence = 0; // 序列号，用于数据包顺序控制
  Mutex _lock = Mutex(); // 互斥锁，防止并发访问
  bool _started = false; // 串口启动状态标志
  String _lastId = ""; // 最后打开的串口ID

  /// 获取所有可用串口列表
  List<Map<String, String>> getAllPorts() {
    // 获取包含完整信息的串口列表
    final r = SerialPort.getPortsWithFullMessages();
    // 转换为Map格式：{端口名: 友好名称}
    return List.generate(
        r.length, (index) => {r[index].portName: r[index].friendlyName});
  }

  /// 获取串口打开状态
  bool get opened {
    if (!_started) return false; // 未启动直接返回false
    return _sp.isOpened; // 返回串口实际打开状态
  }

  /// 打开串口
  Future<bool> open(String portName, int baudRate) async {
    try {
      // 创建串口实例，指定端口名和波特率
      _sp = SerialPort(portName, BaudRate: baudRate);

      // 设置数据接收监听器，每次读取200字节
      _sp.readBytesOnListen(200, _onListen);

      // 如果是重连同一个端口，直接打开
      if (_lastId.isNotEmpty && _lastId == portName) {
        _sp.open();
      }

      // 延迟500ms等待串口稳定
      await 500.milliseconds.delay();
      _started = true; // 标记为已启动
      _lastId = portName; // 记录当前端口ID
      return _sp.isOpened; // 返回打开状态
    } catch (e) {
      _started = false; // 异常时标记为未启动
      return false;
    }
  }

  /// 关闭串口
  void close() {
    // 释放锁（如果被锁定）
    if (_lock.isLocked) {
      _lock.release();
    }
    _sp.close(); // 关闭串口
  }

  /// 发送数据到串口
  bool send(List<int> data) {
    // 将List<int>转换为Uint8List并发送
    return _sp.writeBytesFromUint8List(Uint8List.fromList(data));
  }

  /// 数据接收回调函数
  void _onListen(Uint8List data) {
    print(data.toList()); // 打印接收到的原始数据（调试用）
    _received = true; // 标记已接收到数据
    _receivedData = data.toList(); // 存储接收到的数据
  }

  /// 发送请求并等待响应（请求-响应模式）
  Future<List<int>> sendRequest(RequestBean request) async {
    // 构建数据帧
    final frame = Frame(null);

    // 帧结构：板卡ID + 序列号 + 请求ID + 数据长度 + 数据内容 + 校验位
    frame
        .pushByte(request.boardId) // 板卡标识
        .pushByte(_sequence) // 序列号（防重复、保顺序）
        .pushByte(request.requestId.index) // 请求类型枚举值
        .pushShort(request.dataLength); // 数据长度

    // 如果有数据内容，添加到帧中
    if (request.dataLength > 0) {
      frame.pushList(request.data);
    }

    // 添加异或校验位
    frame.pushByte(frame.xor());

    // 更新序列号（循环0-255，跳过0）
    _sequence = ++_sequence & 0xFF;
    _sequence = _sequence == 0 ? 1 : _sequence;

    try {
      // 获取锁，确保同一时间只有一个请求在发送
      await _lock.acquire();

      int countDown = 25; // 超时计数器（25*10ms=250ms超时）

      while (true) {
        // 重置接收状态
        _received = false;
        _receivedData.clear();

        // 发送数据
        print("====发送数据:${frame.toList()}"); // 调试输出
        send(frame.toList());

        // 等待响应
        while (countDown-- > 0) {
          if (_received) {
            break; // 收到响应，退出等待
          }
          await 10.milliseconds.delay(); // 每10ms检查一次
        }

        if (!_received) {
          print("接受超时"); // 超时处理
          return []; // 返回空列表表示超时
        }

        // 成功接收到数据
        print("----接收数据:${_receivedData}"); // 调试输出
        return _receivedData;
      }
    } catch (e) {
      // 异常处理
      print("串口通信异常: $e");
    } finally {
      // 确保锁被释放
      if (_lock.isLocked) _lock.release();
    }
    return []; // 异常情况下返回空列表
  }
}
